import axios from "axios";
import {axios as AxiosInstance} from "@/units/request"
import store from "@/store/index"
import appStore from "@/store/app"
import {uploaderApi} from "@/api/resources";
import SysConfig from "@/units/config";
import {stringToMd5} from "@/units/md5"
import {typeOf} from "@/units/tool";

/**
 * 本地上传配置类型
 */
export type LocalUploadConfigType = {
    driver: "local",
    type: string,
    host: string,
    extention: string[],
    mimes: string
}


/**
 * oss上传类型
 */
export type OssUploadConfigType = {
    driver: "oss",
    type: string,
    host: string,
    extention: string[],
    mimes: string,
    conf: {
        accessid: string
        dir: string
        expire: number
        host: string
        policy: string
        signature: string
    }
}

/**
 * Cos上传配置类型
 */
export type CosUploadConfigType = {
    driver: "cos",
    type: string,
    host: string,
    extention: string[],
    mimes: string
}


/**
 * 上传配置联合类型
 */
export type UploadConfigType = LocalUploadConfigType | OssUploadConfigType | CosUploadConfigType


/**
 * 进度回调函数
 */
export type ProgressCallback = (progress: number) => void


/**
 * 上传资源数据类型
 */
export type ResultType = {
    drive: string
    format: string
    path: string
    url: string
}

/**
 * 阿里云OSS上传文件-web直传阿里云
 * @constructor
 */
export function OssUploadFile(file: File, config: OssUploadConfigType, callback?: ProgressCallback): Promise<ResultType | null> {
    return new Promise(async resolve => {
        let save: string = config.conf.dir+((Math.random()*1000000).toFixed(0))+ file.name;
        if (save.charAt(0) === '/') {
            save = save.substring(1);
        }
        const ossData: FormData = new FormData();
        ossData.append("name", file.name);
        ossData.append("key", save);//储存地址,不能以/开头
        ossData.append("policy", config.conf.policy);
        ossData.append("OSSAccessKeyId", config.conf.accessid);
        ossData.append("success_action_status", '200');
        ossData.append("signature", config.conf.signature);
        ossData.append("file", file, file.name);
        // @ts-ignore
        let result = await axios.post(config.conf.host, ossData, {
            timeout: 1000 * 3600,
            headers: {"Content-Type": "multipart/form-data"},
            onUploadProgress: progressEvent => {
                // @ts-ignore
                callback && callback((progressEvent.loaded / progressEvent.total * 100 | 0))
            }
        });
        callback && callback(100)
        if (result.status === 200) {
            // @ts-ignore
            const data: ResultType = {drive: config.driver, format: file.name.split('.').pop(), path: `/${save}`, url: `${config.host}/${save}`}
            resolve(data)
        } else {
            resolve(null)
        }
    })
}


/**
 * 腾讯COS上传驱动-web直传腾讯云
 * @constructor
 */
export function CosUploadFile(file: File, config: CosUploadConfigType): Promise<ResultType | null> {
    return Promise.resolve(null)
}


/**
 * 本地上传驱动-上传到本地服务器
 * @constructor
 */
export function LocalUploadFile(file: File, config: LocalUploadConfigType, callback?: ProgressCallback): Promise<ResultType | null> {
    return new Promise(async resolve => {
        const app = appStore(store)
        let blockSize: number = SysConfig.upload_block_size//分片大小
        let blockCount: number = Math.ceil(file.size / blockSize)//分片数
        for (let index = 0; index < blockCount; index++) {
            let start: number = blockSize * index//计算分块开始区域
            let end: number = start + blockSize//计算分块结束分块区域
            if (end > file.size) end = file.size
            let block: Blob = file.slice(start, end)// 文件分块
            let fileData: FormData = new FormData()
            fileData.append("total", blockCount.toString())
            fileData.append("index", (index + 1).toString())
            fileData.append("key", stringToMd5(`${file.name}/${file.size}/${file.lastModified}/${file.type}`, 16))
            fileData.append("type", config.type)
            fileData.append("file", block, file.name)
            // @ts-ignore
            const result = await AxiosInstance({baseURL: app.ext.base_api, timeout: 600000, method: 'POST', url: uploaderApi, data: fileData})
            // @ts-ignore
            if (result.code === 200 && typeOf(result.data) === 'object') {
                // @ts-ignore
                let progress: number = parseFloat((start / file.size * 100))//上传进度
                if (result.data.progress === 'loading') {
                    callback && callback(progress)
                } else if (result.data.progress === 'success') {
                    callback && callback(100)
                    // @ts-ignore
                    const data: ResultType = {drive: config.driver, format: file.name.split('.').pop(), path: result.data.info.path, url: result.data.info.url}
                    resolve(data)
                } else {
                    return resolve(null)
                }
            } else {
                return resolve(null)
            }
        }
    })
}


/**
 * 上传文件
 * @param file   上传对象
 * @param config 上传配置
 * @param callback
 */
export function UploadFile(file: File, config: UploadConfigType, callback?: ProgressCallback): Promise<ResultType | null> {
    if ((config as OssUploadConfigType).driver === 'oss') {//阿里云oss上传驱动
        // @ts-ignore
        return OssUploadFile(file, config, callback)
    } else if ((config as LocalUploadConfigType).driver === 'local') {//本地上传驱动
        // @ts-ignore
        return LocalUploadFile(file, config, callback)
    } else if ((config as CosUploadConfigType).driver === 'cos') {//腾讯COS上传
        // @ts-ignore
        return CosUploadFile(file, config)
    }
    return Promise.resolve(null)
}